﻿<h1>Dispatching</h1>

<p>
    Sometimes, renders need to be triggered in response to non-lifecyle events.
    The current thread will not be associated with the renderer's sync context,
    so the render request has to be marshalled onto that sync context.
</p>

<p>
    Result: <strong id="result">@result</strong>
</p>

<button id="run-without-dispatch" @onclick=RunWithoutDispatch>Run without dispatch</button>
<button id="run-with-dispatch" @onclick=RunWithDispatch>Run with dispatch</button>
<button id="run-with-double-dispatch" @onclick=RunWithDoubleDispatch>Run with double dispatch</button>
<button id="run-async-with-dispatch" @onclick=RunAsyncWorkWithDispatch>Run async work with dispatch</button>

@code {
    string result;

    async Task RunWithoutDispatch()
    {
        await Task.Delay(1).ConfigureAwait(false);
        AttemptToRender();
    }

    async Task RunWithDispatch()
    {
        await Task.Delay(1).ConfigureAwait(false);
        await InvokeAsync(AttemptToRender);

        // So we can observe that the dispatched work item completed by now
        if (result == "Success")
        {
            result += " (completed synchronously)";
        }
    }

    async Task RunWithDoubleDispatch()
    {
        await Task.Delay(1).ConfigureAwait(false);
        await InvokeAsync(() => InvokeAsync(AttemptToRender));

        // So we can observe that the dispatched work item completed by now
        if (result == "Success")
        {
            result += " (completed synchronously)";
        }
    }

    async Task RunAsyncWorkWithDispatch()
    {
        await Task.Delay(1).ConfigureAwait(false);

        result = "First";

        var invokeTask = InvokeAsync(async () =>
        {
            // When the sync context is idle, queued work items start synchronously
            result += " Second";
            await Task.Delay(250);
            result += " Fourth";
        });

        result += " Third";
        await invokeTask;
        result += " Fifth";
    }

    void AttemptToRender()
    {
        try
        {
            result = "Success";
            StateHasChanged();
        }
        catch (Exception ex)
        {
            result = ex.ToString();
        }
    }
}
